#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define N 20

void EndPrint(char Map[N][N], int score, HANDLE hBuffer)
{
    //定义 CHAR_INFO 缓冲区（存储字符 + 颜色）
    CHAR_INFO charBuffer[N + 2][2*N + 2];

    //填充 CHAR_INFO 缓冲区
    //颜色内容：边框：绿色
    //          背景：白色
    //          蛇：黄色
    //          食物：红色
    //得分显示
    //游戏结束弹窗
    char scoreStr[10];
	sprintf(scoreStr, "Score: %d", score);
    for(int i = 0; i < 2*N+2; i++)
	{
		if(i <= (int)strlen(scoreStr) && i > 0)
			charBuffer[0][i].Char.AsciiChar = scoreStr[i-1];
		else
			charBuffer[0][i].Char.AsciiChar = ' ';
		charBuffer[0][i].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
	}
    //上边界
	for(int i = 0; i < 2*N+2; i++)
	{
		charBuffer[1][i].Char.AsciiChar = '-';
		charBuffer[1][i].Attributes = FOREGROUND_GREEN;
	}
	//地图内容
    for (int i = 0; i < N-1; i++)
	{
        //左边界
        charBuffer[i+2][0].Char.AsciiChar = '|';
        charBuffer[i+2][0].Attributes = FOREGROUND_GREEN;

        //地图内容
        for(int j = 0; j < N; j++)
		{
            charBuffer[i+2][2*j+1].Char.AsciiChar = Map[i][j];
            if (Map[i][j] == '@' || Map[i][j] == '*')
                charBuffer[i+2][2*j+1].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | 
				                                    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
            else if (Map[i][j] == 'O')
                charBuffer[i+2][2*j+1].Attributes = FOREGROUND_RED | 
				                                    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
            else
            	charBuffer[i+2][2*j+1].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | 
				                                    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
            charBuffer[i+2][2*j+2].Char.AsciiChar = ' ';
            charBuffer[i+2][2*j+2].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
			                                    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
        }
        //结束弹窗
        char Str[30];
        //弹窗上边界
        if(i == 9)
        {
            sprintf(Str, "-------------------");
            for(int j = 10,k = 0; j < 30; j++)
            {
                charBuffer[i][j].Char.AsciiChar = Str[k++];
				charBuffer[i][j].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
            }
        }
        //弹窗内容
        if(i == 10)
        {
            sprintf(Str, "|    Game Over!   |");
            for(int j = 10,k = 0; j < 30; j++)
            {
                charBuffer[i][j].Char.AsciiChar = Str[k++];
				charBuffer[i][j].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
            }
        }
        if(i == 11)
        {
            sprintf(Str, "| 1.again  2.exit |");
            for(int j = 10,k = 0; j < 30; j++)
            {
                charBuffer[i][j].Char.AsciiChar = Str[k++];
				charBuffer[i][j].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
            }
        }
        //弹窗下边界
        if(i == 12)
        {
            sprintf(Str, "-------------------");
            for(int j = 10,k = 0; j < 30; j++)
            {
                charBuffer[i][j].Char.AsciiChar = Str[k++];
				charBuffer[i][j].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
            }
        }
        //右边界
        charBuffer[i+2][2*N+1].Char.AsciiChar = '|';
		charBuffer[i+2][2*N+1].Attributes = FOREGROUND_GREEN;
    }
    //下边界
	for(int i = 0; i < 2*N+2; i++)
	{
		charBuffer[N+1][i].Char.AsciiChar = '-';
		charBuffer[N+1][i].Attributes = FOREGROUND_GREEN;
	}

    COORD bufferSize = {2*N + 2, N + 2};    //定义写入区域
    COORD bufferCoord = {0, 0};      //从 CHAR_INFO 缓冲区的 (0,0) 开始读取
    SMALL_RECT writeRegion = {0, 0, 2*N + 1, N + 1};   //控制台写入区域

    //使用双缓冲一次性写入字符和颜色
    WriteConsoleOutput(
        hBuffer,    //控制台的屏幕缓冲区（直接输出的缓冲区）
        (CHAR_INFO*)charBuffer,     // CHAR_INFO 缓冲区（预先准备的写入了字符和颜色的缓冲区）
        bufferSize,    //写入的区域
        bufferCoord,    //读取起始点
        &writeRegion    //控制台写入区域
    );

    //重置光标
    SetConsoleCursorPosition(hBuffer, (COORD){0, 0});
}

void EndLogic(char Map[N][N], int score, HANDLE hBuffer)
{
    //打印地图
	EndPrint(Map, score, hBuffer);
	Sleep(500);
    while (1)
	{
        //检测键盘录入
		if(GetAsyncKeyState('1') & 0x8000)
		{
			break;
		}
		if(GetAsyncKeyState('2') & 0x8000)
		{
			break;
		}
		if(GetAsyncKeyState('3') & 0x8000)
		{
			break;
		}
		if(GetAsyncKeyState('4') & 0x8000)
		{
			break;
		}
        EndPrint(Map, score, hBuffer);
        Sleep(100);
    }
}

int main()
{
	//定义双缓冲的句柄
	HANDLE hBuffer = CreateConsoleScreenBuffer(
	    GENERIC_READ | GENERIC_WRITE,	//缓冲区设置为可读（输出）可写（改变状态）
	    FILE_SHARE_READ | FILE_SHARE_WRITE,
	    NULL,	//默认安全属性
	    CONSOLE_TEXTMODE_BUFFER,	//应为程序由字符呈现，故采用文本模式的缓冲区
	    NULL	//无模板
	);
	SetConsoleActiveScreenBuffer(hBuffer); 		//设置为活动缓冲区
	
    //模拟结束时的地图
    char Map[N-1][N];
    for(int i = 0; i < N-1; i++)
	{
		for(int j = 0; j < N; j++)
		{
			Map[i][j] = ' ';
		}
	}
    //定义蛇的长度及所有部位的坐标
    int snake[N*N][2];
	//定义初始蛇各个部位的坐标
    snake[0][0] = N/2; snake[0][1] = N/2;
    snake[1][0] = N/2 + 1; snake[1][1] = N/2;
    snake[2][0] = N/2 + 2; snake[2][1] = N/2;
    //定义食物的坐标和初始分数
    int x, y, score = 20;
    //随机生成食物
    srand(time(NULL));
    x = rand() % (N-1);
    y = rand() % N;
    Map[x][y] = 'O';
    //划归蛇的位置
	Map[snake[0][0]][snake[0][1]] = '@';
	Map[snake[1][0]][snake[1][1]] = '*';
	Map[snake[2][0]][snake[2][1]] = '*';

	EndLogic(Map, score, hBuffer);
	
    //释放资源
    SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
	CloseHandle(hBuffer);
    printf("程序结束\n");
    return 0;
}
